#pragma once

#include "BufferedWnd.h"
#include "Timer.h"

#define POPUP_WND_REFRESH_RATE   40

class CPopupWnd : public CBaseWindow
{
public:
  CPopupWnd()
    : m_tmrTransition(this), m_tStart(0), m_tDuration(0), m_bShow(false)
  {}

public:
// Message map and handlers
	BEGIN_MSG_MAP(CPopupWnd)
    MESSAGE_HANDLER(WM_DESTROY, OnDestroy)

    CHAIN_MSG_MAP(CBaseWindow)
	END_MSG_MAP()

  LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
  {
    if (m_tmrTransition.IsActive())
    {
      ReleaseCapture();
      m_tmrTransition.Stop();
    }
    return bHandled = FALSE;
  }

  virtual void Show(const CRect& rcStart, const CRect& rcEnd, DWORD dwTime);
  virtual void Hide(const CRect& rcEnd, DWORD dwTime);
  virtual void Hide(DWORD dwTime)
  { Hide(m_rcStart, dwTime); }

  void OnTransitionTimer(UINT uTimer, DWORD dwTime);

protected:
  virtual void DoPaint(CDCHandle dc, const CRect& rClip);
  virtual void StopTransition();

protected:
  CTimerInst<CPopupWnd, &CPopupWnd::OnTransitionTimer> m_tmrTransition;
  bool  m_bShow;
  DWORD m_tStart;
  DWORD m_tDuration;
  CRect m_rcStart;
  CRect m_rcEnd;

protected:
  static CScreenDC s_popupbuf;
};


class CModalPopupWnd : public CPopupWnd
{
public:
  CModalPopupWnd() : m_result(IDCANCEL), m_dwHideTime(0)
  {}
  virtual ~CModalPopupWnd()
  {
    if (m_hWnd)
    {
      DestroyWindow();
    }
  }

	HWND Create(HWND hWndParent, _U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
      DWORD dwStyle = WS_POPUP | WS_SYSMENU, DWORD dwExStyle = WS_EX_CAPTIONOKBTN | WS_EX_WINDOWEDGE,
      _U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)
	{
    return CPopupWnd::Create(hWndParent, rect, szWindowName, dwStyle, dwExStyle, MenuOrID, lpCreateParam);
  }

  int DoModal();
  int DoModal(const CRect& rcStart, DWORD dwShowTime = 0, DWORD dwHideTime = 0);
  int DoModal(const CRect& rcStart, const CRect& rcEnd, DWORD dwShowTime = 0, DWORD dwHideTime = 0);

  void EndDialog(int result = IDCANCEL)
  {
    m_result = result;
    Hide(m_dwHideTime);
  }

// Message map and handlers
	BEGIN_MSG_MAP(CModalPopupWnd)
    MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
    MESSAGE_HANDLER(WM_CLOSE, OnClose)
    MESSAGE_HANDLER(WM_SIZE, OnSize)

    MESSAGE_HANDLER(WM_KEYDOWN, OnKeyDown)
    MESSAGE_HANDLER(WM_KEYUP, OnKeyUp)

    MESSAGE_HANDLER(WM_COMMAND, OnCommand)

    CHAIN_MSG_MAP(CPopupWnd)
	END_MSG_MAP()

  LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
  {
    m_endDialog = true;
    CWindow parent = GetParent();
    if (parent.m_hWnd)
      parent.EnableWindow(TRUE);
    return bHandled = TRUE;
  }

  LRESULT OnClose(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
  {
    EndDialog();
    return bHandled = TRUE;
  }

  LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
  {
    if (wParam == SIZE_MINIMIZED)
    {
      DestroyWindow();
      return bHandled = TRUE;
    }
    else
      return bHandled = FALSE;
  }

  LRESULT OnKeyDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  {
    return bHandled = FALSE;
  }

  LRESULT OnKeyUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  {
    switch(wParam)
    {
    case VK_TBACK:
      EndDialog(IDCANCEL);
      return bHandled = TRUE;
    case VK_TACTION:
      EndDialog(IDCANCEL);
      return bHandled = TRUE;
    }

    return bHandled = FALSE;
  }

  LRESULT OnCommand(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
  {
    switch (LOWORD(wParam))
    {
    case IDOK:
    case IDCANCEL:
      EndDialog();
      return bHandled = TRUE;
    }
    return bHandled = FALSE;
  }

protected:
  virtual void StopTransition();

  void ModalLoop();

protected:
  int   m_result;
  bool  m_endDialog;
  DWORD m_dwHideTime;
};